﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.IO;
using System.Reflection;
using GanagroLiteData;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using GeneralUtilities;
using GLiteInterfaces;

namespace GanagroLiteBO
{
	public enum EnumReportes
	{
		GananciaPeriodo,
		GananciaVida,
		VentasVsCompras,
		VentasPeriodo,
		ComprasPeriodo,
		PesajesPeriodo,
		MovimientosPeriodo,
		MuertesPeriodo,
		Inventario,
		PRVDetallado,
		PRVAgrupado,
		Ceba
	}

	public class ListItem
	{
		private String _Description;
		private short _id;

		public short Id
		{
			get { return _id; }
			set { _id = Id; }
		}

		public String Description
		{
			get { return _Description; }
			set { _Description = value; }
		}

		public ListItem() { }
		public ListItem(short id, String Description)
		{
			_id = id;
			_Description = Description;
		}

		public override string ToString()
		{
			return _Description;
		}
	}

	public class PresenterBO
	{
		IreporteView _irv;

		#region Constructors
		public PresenterBO() { }

		public PresenterBO(IreporteView irv)
		{
			_irv = irv;
		}
		#endregion


		public static BindingListView<ListItem> Reportes
		{
			get
			{
				BindingListView<ListItem> R = new BindingListView<ListItem>();
				R.Add(new ListItem((short)EnumReportes.GananciaPeriodo, "Ganancia Diaria por periodo"));
				R.Add(new ListItem((short)EnumReportes.GananciaVida, "Ganancia Vida por periodo"));
				R.Add(new ListItem((short)EnumReportes.Ceba, "Reporte Ceba"));
				R.Add(new ListItem((short)EnumReportes.VentasVsCompras, "Ventas Vs Compras"));
				R.Add(new ListItem((short)EnumReportes.VentasPeriodo, "Ventas por periodo"));
				R.Add(new ListItem((short)EnumReportes.ComprasPeriodo, "Compras por periodo"));
				R.Add(new ListItem((short)EnumReportes.PesajesPeriodo, "Pesajes por periodo"));
				R.Add(new ListItem((short)EnumReportes.MovimientosPeriodo, "Movimientos por periodo"));
				R.Add(new ListItem((short)EnumReportes.MuertesPeriodo, "Muertes por periodo"));
				R.Add(new ListItem((short)EnumReportes.Inventario, "Inventario Detallado"));
				R.Add(new ListItem((short)EnumReportes.PRVDetallado, "Ganancias PRV detalladas"));
				R.Add(new ListItem((short)EnumReportes.PRVAgrupado, "Ganancias PRV agrupadas"));

				return R;
			}
		}

		public static BindingListView<ListItem> Operadores
		{
			get
			{
				BindingListView<ListItem> R = new BindingListView<ListItem>();
				R.Add(new ListItem((short)EnumCompararFecha.menor, "<"));
				R.Add(new ListItem((short)EnumCompararFecha.menorOigual, "<="));
				R.Add(new ListItem((short)EnumCompararFecha.igual, "="));
				R.Add(new ListItem((short)EnumCompararFecha.mayorOigual, ">="));
				R.Add(new ListItem((short)EnumCompararFecha.mayor, ">"));

				return R;
			}

		}


		public void  SetLastFecha(EnumReportes er)
		{
			string whereClause = "where operacion in ({0})";
			string strSql = string.Empty;
			string source = "operaciones";
			DateTime DT = new DateTime();
			switch (er)
			{
				case EnumReportes.GananciaVida:
				case EnumReportes.GananciaPeriodo:
					whereClause = string.Format(whereClause, "1,6,7");
					break;
				case EnumReportes.VentasVsCompras:
				case EnumReportes.VentasPeriodo:
					whereClause = string.Format(whereClause, "7");
					break;
				case EnumReportes.ComprasPeriodo:
					whereClause = string.Format(whereClause, "6");
					break;
				case EnumReportes.MovimientosPeriodo:
					whereClause = string.Format(whereClause, "6,7,9");
					break;
				case EnumReportes.MuertesPeriodo:
					whereClause = string.Format(whereClause, "9");
					break;
				case EnumReportes.PesajesPeriodo :
				case EnumReportes.PRVAgrupado:
				case EnumReportes.PRVDetallado:
					whereClause = string.Format(whereClause, "1");
					source = "pesajes";
					break;
  
				default:
					whereClause = "1=1";
					break;
			}

			strSql = string.Format("select Max(Fecha) from {1} {0} ", whereClause,source);

			DT = DateTime.Parse(UtilityDB.GetVal(strSql));

			this._irv.FechaF = DT;

		}

		public static DateTime GetLastFecha(TiposOperacion tOP )
		{
			DateTime DT;

			try
			{

				string whereClause = string.Empty;

				if (tOP != TiposOperacion.Otras)
				{
					whereClause = string.Format("where operacion = {0}", (short)tOP);
				}

				string tableName =  ((tOP == TiposOperacion.Pesaje_Carne) ? "pesajes" : "operaciones");

				string strSql = string.Format("select Max(Fecha) from {0} {1}",tableName , whereClause);

				DT = DateTime.Parse(UtilityDB.GetVal(strSql));
			}
			catch
			{
				DT = Convert.ToDateTime("1900-01-01");
			}

			return DT;
		}

		public static string GetLastActivities()
		{
			StringBuilder sb = new StringBuilder(string.Empty);
			sb.Append(string.Format("Ultima compra  : {0}\r\n", GetLastFecha(TiposOperacion.compra).ToShortDateString()));
			sb.Append(string.Format("Ultimo pesaje de control : {0}\r\n", GetLastFecha(TiposOperacion.Pesaje_Carne).ToShortDateString()));
			sb.Append(string.Format("Ultima venta  : {0}\r\n", GetLastFecha(TiposOperacion.venta).ToShortDateString()));
			sb.Append(string.Format("Ultima muerte : {0}\r\n", GetLastFecha(TiposOperacion.Muerte).ToShortDateString()));
		  
			return sb.ToString();
		}

		public void GuessAndSetFechaInicial(EnumReportes er)
		{
			switch (er)
			{
				case EnumReportes.GananciaVida:
					this._irv.FechaI = this._irv.FechaF.AddYears(-2);
					break;
				case EnumReportes.VentasVsCompras:
					this._irv.FechaI = this._irv.FechaF.AddYears(-1);
					break;
				case EnumReportes.VentasPeriodo:
				case EnumReportes.ComprasPeriodo:
					this._irv.FechaI = this._irv.FechaF;
					break;
				case EnumReportes.Inventario:
					break;
				default:
					this._irv.FechaI = this._irv.FechaF.AddYears(-2);
					break;
			}
		}

		public static DataTable GetFechas(EnumReportes er)
		{
			string whereClause = "where operacion in ({0})" ; 
			string strSql = string.Empty;
			DataTable DT = new DataTable();
			try 
			{	        
		
			switch (er)
			{
				case EnumReportes.GananciaVida:
				case EnumReportes.GananciaPeriodo:
					whereClause = string.Format(whereClause,"1,6,7");
					break;
				case EnumReportes.VentasVsCompras:
					whereClause = string.Format(whereClause,"6,7");
					break;
				case EnumReportes.VentasPeriodo:
					whereClause = string.Format(whereClause,"7");
					break;
				case EnumReportes.ComprasPeriodo:
					whereClause = string.Format(whereClause,"6");
					break;
				case EnumReportes.MovimientosPeriodo:
					whereClause = string.Format(whereClause,"6,7,9");
					break;
				case EnumReportes.MuertesPeriodo:
					whereClause = string.Format(whereClause,"9");
					break;
				default:
					break;
			}

			strSql = string.Format("select distinct Fecha from operaciones {0} order by fecha desc",whereClause);

			DT = UtilityDB.PopulateDTFromSQL(strSql);

			  return DT;
			}
			finally 
				{
					DT.Dispose();

				}
		}
	

		private static string buildStringGananciaPeriodo(ReportArgs rArgs)
		{
			string strSql = "SELECT O1.Codigo AS Codigo,O1.FECHA AS [Fecha Inicial], O1.Peso AS [Peso Inicial]," +
			"O2.FECHA AS [Fecha Final],O2.Peso AS [Peso Final]," +
			"datediff(dd,O1.FECHA,O2.FECHA) as Dias, " +
			"CASE O1.PESO WHEN 0 THEN NULL " +
			"ELSE ROUND((cast((O2.PESO-O1.PESO) as float)/datediff(dd,O1.FECHA,O2.FECHA))*1000,0)  END AS Ganancia " +
			"FROM PESAJES AS O1 INNER JOIN PESAJES AS O2 ON O1.Codigo = O2.Codigo" +
			string.Format(" WHERE [O1].[FECHA] < [O2].[FECHA] AND O1.PESO > 0 AND " +
			" [O1].[FECHA]  = (SELECT MIN(FECHA) FROM PESAJES P WHERE P.CODIGO = O1.CODIGO AND P.FECHA {0} '{1}') AND " +
			" [O2].[FECHA]  = (SELECT MAX(FECHA) FROM PESAJES P WHERE P.CODIGO = O2.CODIGO AND P.FECHA {2} '{3}') ",
			(rArgs.MatchesFechaI ? "=" : ">="), rArgs.FechaI,
			WhereClauseBuilder.getFechaCompareOperator(rArgs.MatchesFechaF), rArgs.FechaF) +
			" AND " + WhereClauseBuilder.GetActivosInactivosClause(rArgs, "O1.");

			return strSql;
		}




		public DataTable GetReportData(ReportArgs rArgs)
		{
			string strSql = string.Empty;
			string whereClause = WhereClauseBuilder.BuildWhereClause(rArgs);
			string fechaI = rArgs.MatchesFechaI ? string.Format("'{0}'", rArgs.FechaI.ToShortDateString()) : "NULL";
			string fechaF = rArgs.MatchesFechaF == EnumCompararFecha.igual ? string.Format("'{0}'", rArgs.FechaF.ToShortDateString()) : "NULL";
			PresenterSummaryData pSummary = new PresenterSummaryData(_irv);

			try
			{
				switch ((EnumReportes)rArgs.ReportNumber)
				{
					case EnumReportes.GananciaVida:
						strSql = string.Format("SELECT Codigo,FechaInicial as [Fecha Inicial], PesoInicial as [Peso Inicial], FechaFinal AS [Fecha Final], Pesofinal as [Peso Final], GananciaDia as Ganancia FROM RepGananciaVida {0} ", whereClause);
						pSummary.SummaryGananciaVida(rArgs);
						break;
					case EnumReportes.GananciaPeriodo:
						// In this case the Where clause is built inside of buildStringGananciaPeriodo(rArgs)
						strSql = buildStringGananciaPeriodo(rArgs);
						pSummary.SummaryGananciasPeriodo(rArgs, strSql);
						strSql = strSql + " ORDER BY 2";
						break;
					case EnumReportes.Ceba:
						strSql = string.Format("SELECT Codigo,Peso,Fecha1,Fecha2,Fecha3,UltGan,GVida as [G. Vida],round(PesoHoy,0) as [Peso Hoy]  FROM ANALISIS_CEBA {0} ", whereClause);
						pSummary.ReporteCebaSummary(rArgs);
						break;
					case EnumReportes.VentasVsCompras:
						strSql = string.Format("SELECT Codigo,fecha_venta as [Fecha Venta],peso_venta as [Peso Venta],Precio_kilo as [Precio Kilo]," +
											   "Fecha_compra as [Fecha Compra], Kilos_compra as [Peso (c)],Costo_kilo as [Costo Kilo], " +
											   "GananciaDiariaPesos as [G/dia (Pesos)],GananciaDiariaGramos as [G/dia (Gramos)] " +
											   " FROM VentasVsCompras {0} ", whereClause);
						pSummary.VentasVsCompras(rArgs);
						break;
					case EnumReportes.VentasPeriodo:
						strSql = string.Format("SELECT * FROM Ventas {0} ", whereClause);
						pSummary.SummaryVentas(rArgs);
						break;
					case EnumReportes.ComprasPeriodo:
						strSql = string.Format("SELECT * FROM compras {0} ", whereClause);
						pSummary.SummaryCompras(rArgs);
						break;
					case EnumReportes.MovimientosPeriodo:
						strSql = string.Format("SELECT FECHA, OPERACION, TOTAL FROM RepMovimientos {0} ", whereClause);
						pSummary.SummaryMvtos(rArgs);
						break;
					case EnumReportes.PesajesPeriodo:
						strSql = string.Format("SELECT Fecha, Codigo, Peso FROM Pesajes {0} order by Fecha,ID", whereClause);
						pSummary.SummaryPesajes(rArgs);
						break;
					case EnumReportes.MuertesPeriodo:
						strSql = string.Format("SELECT * FROM Muertes {0} ", whereClause);
						break;
					case EnumReportes.Inventario:
						whereClause = string.Format(" WHERE 1=1 {0} ", WhereClauseBuilder.GetRangoCodigos(rArgs));
						strSql = string.Format("SELECT [CODIGO],[Color],[Raza],UltimoPeso AS [Peso], Fecha [Fecha Pesaje],[Tatuaje] FROM InventarioDetallado {0} ", whereClause);
						break;
					case EnumReportes.PRVDetallado:
						strSql = string.Format("SELECT Codigo,Peso,Fecha1,Fecha2,Fecha3,UltGan,GVida as [G. Vida],round(PesoHoy,0) as [Peso Hoy]   FROM ANALISIS_CEBA_PRV ({0},{1})", fechaI, fechaF);
						break;
					case EnumReportes.PRVAgrupado:
						strSql = string.Format("SELECT * FROM PRV_GB ({0},{1})", fechaI, fechaF);
						break;

					default:
						break;
				}

				Int32 numCols = 0;
				DataTable Dt = UtilityDB.PopulateDTFromSQL(strSql, ref numCols);

				SetMedian(Dt, getColumnaReporte(rArgs.ReportNumber));

				if (rArgs.ReportNumber != EnumReportes.MovimientosPeriodo)
				{
					this._irv.TotalSemovientes = string.Format("Total: {0} Semovientes", Dt.Rows.Count);
				}

				rArgs.NumeroColumnasGrid = numCols;

				return Dt;

			}
			catch (Exception)
			{

				throw;
			}
		}


		private static string getColumnaReporte(EnumReportes enumReporte)
		{
			string strSql = string.Empty;
			switch (enumReporte)
			{
				case EnumReportes.GananciaVida:
					strSql = "Ganancia";
					break;
				case EnumReportes.GananciaPeriodo:
					strSql = "Ganancia";
					break;
				case EnumReportes.Ceba:
					strSql = "G. Vida";
					break;
				case EnumReportes.VentasVsCompras:
					strSql = "G/dia (Gramos)";
					break;
				case EnumReportes.VentasPeriodo:
					break;
				case EnumReportes.ComprasPeriodo:
					break;
				case EnumReportes.MovimientosPeriodo:
					break;
				case EnumReportes.PesajesPeriodo:
					strSql = "Peso";
					break;
				case EnumReportes.MuertesPeriodo:
					break;
				case EnumReportes.Inventario:
					strSql = "Peso";
					break;
				case EnumReportes.PRVDetallado:
					strSql = "G. Vida";
					break;
				case EnumReportes.PRVAgrupado:
					break;
				default:
					break;
			}

			return strSql;
		}

		private void SetMedian(DataTable Dt, string fieldName)
		{
			if (!string.IsNullOrEmpty(fieldName))
			{
				var ct = Dt.AsEnumerable().Count();
				if (ct > 1)
				{
					int ct2=0;
					bool isdouble = false;
					try
					{
						ct2 = Dt.AsEnumerable().Where(dr => dr.Field<double?>(fieldName) == null).Count();
						isdouble = true;
					}
					catch
					{
						// TODO: Find proper type from query below 
						//  var dtlFieldNames = Dt.Columns.Cast<DataColumn>().
						//   Select(item => new{Name = item.ColumnName,Type = item.DataType}).ToList();
					}

					double? median = 0;

					if (ct > 3)
					{
						int medianIndex = (ct2) + ((ct - ct2) / 2);
						if (isdouble)
						{
							var query = Dt.AsEnumerable().OrderBy(dr => dr.Field<double?>(fieldName));
							median = query.ElementAt(medianIndex).Field<double?>(fieldName);
						}
						else
						{
							var query = Dt.AsEnumerable().OrderBy(dr => dr.Field<Int16>(fieldName));
							median = query.ElementAt(medianIndex).Field<Int16>(fieldName);
						}
					}

					this._irv.SummaryData3 = string.Format("Media: {0}", median);
				}
			}
		}


		public void PoblarFechasAfinesAlReporte(EnumReportes ReportNumber)
		{
			switch (ReportNumber)
			{
				case EnumReportes.Inventario:
				case EnumReportes.Ceba:
					break;
				default:
					this.SetLastFecha(ReportNumber);
					this.GuessAndSetFechaInicial(ReportNumber);
					break;
			}
		}

		// Get Median
//        SELECT
//(
// (SELECT MAX(GananciaDia) FROM
//   (SELECT TOP 50 PERCENT GananciaDia FROM RepGananciaVida ORDER BY GananciaDia) AS BottomHalf)
// +
// (SELECT MIN(GananciaDia) FROM
//   (SELECT TOP 50 PERCENT GananciaDia FROM RepGananciaVida ORDER BY GananciaDia DESC) AS TopHalf)
//) / 2 AS Median

	}

}
